package common

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net"

	"google.golang.org/grpc"
)

var AccessServiceInfo = ServiceInfo{ServiceType: SERVICE_TYPE_ACCESS}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func MakeNilResMsg(rid string, cmd string, code int, msg string) Message {
	return Message{
		Rid: rid,
		Cmd: cmd,
		Data: ResMsgData{
			Code: code,
			Msg:  msg,
		},
	}
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func MakeNilSuccessResMsg(rid string, cmd string) Message {
	return MakeNilResMsg(rid, cmd, 0, "success")
}

// -------------------------------------------------------------------------------------------------
// @brief 启动 GRPC 服务
// @param serviceName 服务名称
// @param initFunc    初始化函数
// @param addr        服务地址
// -------------------------------------------------------------------------------------------------
type InitDaoFunc func(ctx context.Context, server *grpc.Server) error

func StartRpcServer(serviceName string, initFunc InitDaoFunc, addr string) {
	// 创建GRPC服务器
	server := grpc.NewServer()

	// 调用外部初始化函数
	if err := initFunc(context.Background(), server); err != nil {
		Logger(MODULE_COMMON).Error("Failed to initialize grpc server", err)
		return
	}

	// 开始监听
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		Logger(MODULE_COMMON).WithError(err).WithField("addr", addr).Error("failed to listen")
		return
	}
	Logger(MODULE_COMMON).WithField("addr", addr).Info("server listening")

	// 启动服务
	if err := server.Serve(listener); err != nil {
		Logger(MODULE_COMMON).WithError(err).Error("failed to serve")
	}
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func ToJson[T any](data T) string {
	result, err := json.Marshal(data)
	if err != nil {
		return "Invalid!!!"
	}
	return string(result)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func GenerateRandomStr(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	result := make([]byte, length)
	for i := range result {
		result[i] = charset[rand.Intn(len(charset))]
	}
	return string(result)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func CompareMediaInfo(a, b MediaInfo) bool {
	return a.MediaId == b.MediaId
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func Clone(dst, source any) error {
	data, err := json.Marshal(source)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, dst)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func Ref(b bool) *bool {
	return &b
}

type AppError struct {
	ErrCode int    // 错误码，用于客户端识别
	ErrMsg  string // 错误信息，用于日志和调试
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func (e AppError) Error() string {
	return fmt.Sprintf("app error (code: %d): %s", e.ErrCode, e.ErrMsg)
}

// -------------------------------------------------------------------------------------------------
//
// -------------------------------------------------------------------------------------------------
func ValidateMediaInfo(media MediaInfo) error {
	if media.MediaId == "" {
		return errors.New("media_id is required")
	}
	return nil
}
